using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Data;
using System.Net;

namespace SrWinGui
{
    public sealed class Ripper
    {
        private Process p;
        #region classdeclarations
        private static readonly Ripper instance = new Ripper();
        private DataTable songsTable;
        private bool processHasEverStarted = false;
        private Ripper()
        {
            p = new Process();
            p.StartInfo.FileName = "streamripper.exe";     
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;


            myBuffer = new StringCollection();
            
            songsTable = new DataTable("Songs");
            songsTable.Columns.Add("Title", typeof(string));
            songsTable.Columns.Add("Size", typeof(string));
            songsTable.Columns.Add("Status", typeof(string));
            songsTable.PrimaryKey = new DataColumn[] { songsTable.Columns["Title"] };


        }
        public static Ripper Instance
        {
            get
            {
                return instance;
            }
        }
        #endregion
        private string stream, serverName, bitrate, metaInterval, status;
        private StringCollection myBuffer;
        
        
        //dichiaro le variabili
        public string Stream
        {
            get
            {
                return stream;
            }
        }
        public string ServerName
        {
            get
            {
                return serverName;
            }
        }
        public string Bitrate
        {
            get
            {
                return bitrate;
            }
        }
        public string MetaInterval
        {
            get
            {
                return metaInterval;
            }
        }
        public string Status
        {
            get
            {
                return status;
            }
        }
        public DataTable SongsTable
        {
            get { return songsTable; }
        }
        
        public void StartRipping(string url)
        {
            p.StartInfo.Arguments = url + Impostazioni.Instance.GetArguments();
            this.processHasEverStarted = p.Start();

            //clean buffer for io
            if (myBuffer != null)
                myBuffer.Clear();

            //begin reading of output
            Thread t1 = new Thread(readOutput);
            t1.Start(p.StandardError);
            

            //process waiting for cleaning
            Thread t2 = new Thread(cleaner);
            t2.Start(p);

        }
        private void readOutput(object osr)
        {
            StreamReader sT = (StreamReader)osr;
            string line;
            while ((line = sT.ReadLine()) != null)
                addLine(line);
        }
        private void addLine(string line)
        {
            /*
            Connecting...
            stream: -=- MPEGRadio.Com -=- tormented radio / djdead
            server name: SHOUTcast/Linux v1.9.5
            bitrate: 128
            meta interval: 8192

            [buffering - | ] Hocico - Poltergeist
            [ripping...    ] Lights of Euphoria - Lost and Found [  768kb]
            [ripping...    ] Wolfsheim - Approaching Lightspeed [  3,13M]
            [ripping...    ] Funker Vogt - House Of Sorrows [  5,01M]
            [ripping...    ] Nevarakka - Obsession [  4,63M]
            [ripping...    ] Amduscia - Freak Knowledge [  4,08M]
            [ripping...    ] And One - speicherbar [  3,77M]
            [ripping...    ] Monofader - Deliver [  4,11M]
            [ripping...    ] Covenant - Spindrift [  6,37M]
            [ripping...    ] Tristraum - Toothing [  4,75M]
            [ripping...    ] Tristesse De La Lune - Ninive (Amduscia 612 B.C.) [    1kb]*/
            int numRows = myBuffer.Count;
            switch(numRows)
            {
                case 0:
                    this.status = line;
                    break;
                case 1:
                    //check if i'm in the middle of capture or error
                    Match m = Regex.Match(line, "stream: (.*)");
                    if (m.Success)
                        this.stream = m.Groups[1].Value;
                    else
                        throw (new ArgumentException("Error 1"));
                    break;
                case 2:
                    this.serverName = Regex.Match(line, "server name: (.*)").Groups[1].Value;
                    break;
                case 3:
                    this.bitrate = Regex.Match(line, "bitrate: ([0-9]+)").Groups[1].Value;
                    break;
                case 4:
                    this.metaInterval = Regex.Match(line, "meta interval: [0-9]+").Groups[1].Value;
                    break;
                default:
                    if (line != "")
                    {
                        if (Regex.Match(line, @"\[buffering - | \][A-z]+").Success)
                            this.status = "Buffering";
                        else
                        {
                            m = Regex.Match(line, @"\[(.*?)\](.*?)\[(.*?)\]");
                            if (m.Success)
                            {
                                string stat = m.Groups[1].Value;
                                string title = m.Groups[2].Value;
                                string size = m.Groups[3].Value;
                                if (songsTable.Rows.Count == 0)
                                {
                                    songsTable.Rows.Add(new string[] { title, size, stat });
                                    break;
                                }
                                else
                                {
                                    DataRow row = songsTable.Rows.Find(title);
                                    if (row != null)
                                    {
                                        row.BeginEdit();
                                        row["Size"] = size;
                                        row.EndEdit();
                                    }
                                    else
                                    {
                                        //set previous rows status to done
                                        row = songsTable.Rows[songsTable.Rows.Count - 1];
                                        row.BeginEdit();
                                        row["Status"] = "Done";
                                        row.EndEdit();
                                        songsTable.Rows.Add(new string[] { title, size, stat });                                        
                                    }
                                }
                            }
                        }
                    }
                    break;
            }
            myBuffer.Add(line);

        }
        private void cleaner(object opr)
        {
            Process pr = (Process)opr;
            while (!pr.HasExited)
                Thread.Sleep(300);
            //TODO add Cleaning
        }
        public void DownloadStationInfo(object parameters)
        {
            string stationID = (string)parameters;
            WebClient client = new WebClient();
            string playlist = client.DownloadString("http://www.shoutcast.com/sbin/shoutcast-playlist.pls?rn=" + stationID);
            String url = Regex.Match(playlist, "File.=(.*)").Groups[1].Value;
            if (url == "")
                throw new ArgumentException("No url found");
            StartRipping(url);
        }
        
        public void KillRipping()
        {
            if (processHasEverStarted && p != null && !p.HasExited)
                p.Kill();
        }
    }
}
